﻿
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace S7Communication
{
    public class SendBufferCompile
    {
        private static object connectLocker = new object();
        private static object communicationtLocker = new object();
        private static object readLocker =new object();
        private static object writeLocker = new object();
        private static object itemLocker = new object();
        private static object dataLocker = new object();
        /// <summary>
        /// 建立会话buffer
        /// </summary>
        /// <param name="rack"></param>
        /// <param name="solt"></param>
        /// <returns></returns>
        public static byte[] ReqConnectBuffer(ushort destinationRef, ushort sourcenRef, ushort rack, ushort solt)
        {
            lock (connectLocker)
            {
                byte[] bytes = new byte[22];
                //会话层4byte
                bytes[0] = 0x03;//版本号
                bytes[1] = 0x00;//保留
                Array.Copy(BitConverter.GetBytes(0x0016).Reverse().ToArray(), 0, bytes, 2, 2);//总长度
                //表示层18byte
                bytes[4] = 0x11;//表示层长度（不算自己）
                bytes[5] = 0x0e;//pud类型-连接请求
                Array.Copy(BitConverter.GetBytes(destinationRef).Reverse().ToArray(), 0, bytes, 6, 2);//目标引用
                Array.Copy(BitConverter.GetBytes(sourcenRef).Reverse().ToArray(), 0, bytes, 8, 2);//源引用
                bytes[10] = 0x00;//扩展格式/流控制
                                 //参数
                bytes[11] = 0xc0;//param1_code:TPDU-Sise
                bytes[12] = 0x01;//param1_length
                bytes[13] = 0x0a;//param1_data
                bytes[14] = 0xc1;//param2_code:SRC-TASP/Rack
                bytes[15] = 0x02;//param2_length
                Array.Copy(BitConverter.GetBytes(rack).Reverse().ToArray(), 0, bytes, 16, 2);//param2_data
                bytes[18] = 0xc2;//param3_code:DST-TASP/Solt
                bytes[19] = 0x02;//param3_length
                Array.Copy(BitConverter.GetBytes(solt).Reverse().ToArray(), 0, bytes, 20, 2);//param3_data
                return bytes;
            }
        }
        /// <summary>
        /// 数据传输，建立通信
        /// </summary>
        /// <returns></returns>
        public static byte[] ReqStepCommunicationBuffer(ushort destinationRef, ushort SequenceID)
        {
            lock (communicationtLocker)
            {
                byte[] bytes = new byte[22];
                //会话层4byte
                bytes[0] = 0x03;//版本号
                bytes[1] = 0x00;//保留
                Array.Copy(BitConverter.GetBytes(0x001a).Reverse().ToArray(), 0, bytes, 2, 2);//总长度
                                                                                              //表示层18byte
                bytes[4] = 0x02;//长度
                bytes[5] = (byte)COTP_PDU_TYPE.DT;
                Array.Copy(BitConverter.GetBytes(destinationRef).Reverse().ToArray(), 0, bytes, 6, 2);//目标引用
                                                                                                      //Header
                bytes[8] = 0x32;//协议id
                bytes[9] = (byte)DT_ROSCTR.JOB;
                bytes[10] = 0x00;//预留
                bytes[11] = 0x00;//预留
                Array.Copy(BitConverter.GetBytes(SequenceID), 0, bytes, 12, 2);//协议序列，每次请求+1
                Array.Copy(BitConverter.GetBytes(0x0008).Reverse().ToArray(), 0, bytes, 14, 2);//参数长度
                Array.Copy(BitConverter.GetBytes(0x0000).Reverse().ToArray(), 0, bytes, 16, 2);//数据长度
                                                                                               //parameter
                bytes[18] = 0xf0;//功能码-建立通信
                bytes[19] = 0x00;//预留
                Array.Copy(BitConverter.GetBytes(0x0001).Reverse().ToArray(), 0, bytes, 20, 2);//最大AmQ(Calling)
                Array.Copy(BitConverter.GetBytes(0x0001).Reverse().ToArray(), 0, bytes, 22, 2);//最大AmQ(Called)
                Array.Copy(BitConverter.GetBytes(0x03c0).Reverse().ToArray(), 0, bytes, 24, 2);//协商pdu长度-0x03c0-960
                return bytes;
            }
        }
        /// <summary>
        /// 数据传输，读取值编译
        /// </summary>
        /// <returns></returns>
        public static byte[] ReqReadBuffer(ushort destinationRef, ushort SequenceID, Variable[] readItems)
        {
            lock (readLocker)
            {
                if (readItems == null) { throw new Exception(nameof(readItems) + "为空"); }
                List<byte> bytes = new List<byte>();
                //item
                foreach (Variable reqItem in readItems)
                {
                    bytes.AddRange(ReqItemBuffer(reqItem));
                }
                byte[] bytesTemp = new byte[20];
                //会话层4byte
                bytesTemp[0] = 0x03;//版本号
                bytesTemp[1] = 0x00;//保留
                Array.Copy(BitConverter.GetBytes((ushort)bytesTemp.Length + (ushort)bytes.Count).Reverse().ToArray(), 0, bytesTemp, 2, 2);//总长度
                                                                                                                                          //表示层18byte
                bytesTemp[4] = 0x02;//长度
                bytesTemp[5] = (byte)COTP_PDU_TYPE.DT;
                Array.Copy(BitConverter.GetBytes(destinationRef).Reverse().ToArray(), 0, bytesTemp, 6, 2);//目标引用
                                                                                                          //Header
                bytesTemp[8] = 0x32;//协议id
                bytesTemp[9] = (byte)DT_ROSCTR.JOB;
                bytesTemp[10] = 0x00;//预留
                bytesTemp[11] = 0x00;//预留
                Array.Copy(BitConverter.GetBytes(SequenceID), 0, bytesTemp, 12, 2);//协议序列，每次请求+1
                Array.Copy(BitConverter.GetBytes((ushort)bytes.Count).Reverse().ToArray(), 0, bytesTemp, 14, 2);//参数长度
                Array.Copy(BitConverter.GetBytes(0x0000).Reverse().ToArray(), 0, bytesTemp, 16, 2);//数据长度
                                                                                                   //parameter
                bytesTemp[18] = (byte)DT_PARAMETER_FUCTION.Read_Variable;
                bytesTemp[19] = (byte)readItems.Length;
                bytes.InsertRange(0, bytesTemp);
                return bytes.ToArray();
            }
        }
        /// <summary>
        /// 数据传输，写入值编译
        /// </summary>
        /// <returns></returns>
        public static byte[] ReqWriteBuffer(ushort destinationRef, ushort SequenceID, Variable[] reqItems)
        {
            lock (writeLocker)
            {
                if (reqItems == null) { throw new Exception(nameof(reqItems) + "为空"); }
                byte[] bytesTemp = new byte[20];
                List<byte> bytes = new List<byte>();
                ushort paramsLength;
                ushort datasLength;
                //item
                foreach (Variable reqItem in reqItems)
                {
                    bytes.AddRange(ReqItemBuffer(reqItem));
                }
                paramsLength = (ushort)(bytes.Count + 2);
                //data
                foreach (Variable reqItem in reqItems)
                {
                    bytes.AddRange(ReqDataBuffer(reqItem));
                }
                datasLength = (ushort)(bytes.Count - paramsLength);
                //会话层4byte
                bytesTemp[0] = 0x03;//版本号
                bytesTemp[1] = 0x00;//保留
                Array.Copy(BitConverter.GetBytes((ushort)(paramsLength + datasLength + 18)).Reverse().ToArray(), 0, bytesTemp, 2, 2);//总长度
                                                                                                                                     //表示层18byte
                bytesTemp[4] = 0x02;//长度
                bytesTemp[5] = (byte)COTP_PDU_TYPE.DT;
                Array.Copy(BitConverter.GetBytes(destinationRef), 0, bytesTemp, 6, 2);//目标引用
                                                                                      //Header
                bytesTemp[8] = 0x32;//协议id
                bytesTemp[9] = (byte)DT_ROSCTR.JOB;
                bytesTemp[10] = 0x00;//预留
                bytesTemp[11] = 0x00;//预留
                Array.Copy(BitConverter.GetBytes(SequenceID), 0, bytesTemp, 12, 2);//协议序列，每次请求+1
                Array.Copy(BitConverter.GetBytes(paramsLength).Reverse().ToArray(), 0, bytesTemp, 14, 2);//参数长度
                Array.Copy(BitConverter.GetBytes(datasLength).Reverse().ToArray(), 0, bytesTemp, 16, 2);//数据长度
                                                                                                        //parameter
                bytesTemp[18] = (byte)DT_PARAMETER_FUCTION.Read_Variable;//
                bytesTemp[19] = (byte)reqItems.Length;
                bytes.InsertRange(0, bytesTemp);
                return bytes.ToArray();
            }
        }
        private static byte[] ReqDataBuffer(Variable reqItem)
        {
            lock (dataLocker)
            {
                List<byte> bytes = new List<byte>();
                bytes.Add((byte)DT_RETRUN_CODE.Reserved);
                bytes.Add((byte)reqItem.transportSizes);
                bytes.AddRange(BitConverter.GetBytes(reqItem.dataLength).Reverse().ToList());
                bytes.AddRange(reqItem.data);
                return bytes.ToArray();
            }
        }
        private static byte[] ReqItemBuffer(Variable reqItem)
        {
            lock (itemLocker)
            {
                byte[] bytes = new byte[11];
                bytes[0] = 0x12;
                bytes[1] = 0x0a;
                bytes[2] = (byte)reqItem.syntaxId;
                bytes[3] = (byte)reqItem.transportSizes;
                Array.Copy(BitConverter.GetBytes(reqItem.dataLength).Reverse().ToArray(), 0, bytes, 4, 2);
                Array.Copy(BitConverter.GetBytes(reqItem.dbNumber).Reverse().ToArray(), 0, bytes, 6, 2);
                bytes[8] = (byte)reqItem.area;
                Array.Copy(BitConverter.GetBytes(reqItem.adrress).Skip(1).Reverse().ToArray(), 0, bytes, 9, 3);
                return bytes;
            }
        }
    }
}
